﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
//using SynapseGaming.LightingSystem.Core;

namespace The_LarX
{
    public class Renderer_Cartoon : Renderer
    {
        /*public Effect PostProcEffect;
                
        private RenderTarget2D DepthTarget;
        private RenderTarget2D SceneTarget;

        private List<ILight> Lights;
        private List<Actor> Actors;

        public float EdgeWidth = 1;
        public float EdgeIntensity = 1;

        public bool ApplyToonOnlyLastLight = false;
        
        public Renderer_Cartoon()
        {
#if !WINDOWS_PHONE
            Effect = Engine.Content.Load<Effect>("Engine\\Effects\\fx_Advanced");

            PostProcEffect = Engine.Content.Load<Effect>("Engine\\Effects\\Cartoon\\fx_PostProc");

            PresentationParameters pp = Engine.GraphicsDevice.PresentationParameters;

            DepthTarget = new RenderTarget2D(Engine.GraphicsDevice,
                                                         pp.BackBufferWidth, pp.BackBufferHeight, false,
                                                         pp.BackBufferFormat, pp.DepthStencilFormat);

            SceneTarget = new RenderTarget2D(Engine.GraphicsDevice,
                                             pp.BackBufferWidth, pp.BackBufferHeight, false,
                                             pp.BackBufferFormat, pp.DepthStencilFormat);

            Lights = new List<ILight>();
            Actors = new List<Actor>();

#endif
        }
        private void Reload()
        {
            Effect = Engine.Content.Load<Effect>("Engine\\Effects\\fx_Advanced");

            PostProcEffect = Engine.Content.Load<Effect>("Engine\\Effects\\Cartoon\\fx_PostProc");

            PresentationParameters pp = Engine.GraphicsDevice.PresentationParameters;

            DepthTarget = new RenderTarget2D(Engine.GraphicsDevice,
                                                         pp.BackBufferWidth, pp.BackBufferHeight, false,
                                                         pp.BackBufferFormat, pp.DepthStencilFormat);

            SceneTarget = new RenderTarget2D(Engine.GraphicsDevice,
                                             pp.BackBufferWidth, pp.BackBufferHeight, false,
                                             pp.BackBufferFormat, pp.DepthStencilFormat);
        }

        private List<Model> models = new List<Model>();
        public override void RemapModel(ref Model Model)
        {
#if !WINDOWS_PHONE
            if (Effect.IsDisposed)
                Reload();
            if (!models.Contains(Model))
            {
                models.Add(Model);
                foreach (ModelMesh mesh in Model.Meshes)
                {
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    {
                        Effect newEffect = Effect.Clone();
                        meshPart.Effect = newEffect;
                    }
                }
            }    
#endif
        }

        public override void SubmitActor(Actor actor)
        {            
            Actors.Add(actor);
        }

        public override void SubmitLight(object Light)
        {
            if (Light is ILight)
            {
                Lights.Add((ILight)Light);
            }
        }

        /// <summary>
        /// This renderer sets renderTargets. Set this if you want the Renderer to 
        /// automatically set a RenderTarget after rendering
        /// </summary>
        public RenderTarget2D PreviousRenderTarget;
        /// <summary>
        /// Render all the Stored Actors, with the Stored Lights. This method
        /// WILL clear the BackBuffer
        /// </summary>
        public override void RenderActors()
        {
            if (Camera != null)
            {
                Engine.GraphicsDevice.SetRenderTarget(DepthTarget);
                Engine.GraphicsDevice.Clear(Color.Transparent);
                for (int i = 0; i < Actors.Count; i++)
                {
                    DrawActor(Actors[i], "NormalDepth");
                }

                Engine.GraphicsDevice.SetRenderTarget(SceneTarget);
                Engine.RenderManager.Clear();
                if (this.BeforeTheSceneIsRendered != null)
                    BeforeTheSceneIsRendered();
                for (int i = 0; i < Actors.Count; i++)
                {
                    DrawActor(Actors[i], "Cartoon");
                }
                if (PreviousRenderTarget != null)
                    Engine.GraphicsDevice.SetRenderTarget(PreviousRenderTarget);
                else
                    Engine.GraphicsDevice.SetRenderTarget(null);

                ApplyPostProcess();

                if (this.AfterTheSceneIsRendered != null)
                    AfterTheSceneIsRendered();
            }
            Actors.Clear();
            Lights.Clear();
        }

        private void DrawActor(Actor actor, string technique)
        {
            // Set suitable renderstates for drawing a 3D model.
            Engine.GraphicsDevice.BlendState = BlendState.Opaque;
            Engine.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            // Look up the bone transform matrices.
            Matrix[] transforms = new Matrix[actor.Model.Bones.Count];

            actor.Model.CopyAbsoluteBoneTransformsTo(transforms);

            // Draw the model.
            foreach (ModelMesh mesh in actor.Model.Meshes)
            {
                foreach (Effect effect in mesh.Effects)
                {
                    if (effect is BasicEffect)
                    {
                        Model model = actor.Model;
                        RemapModel(ref model);
                        return;
                    }
                    // Specify which effect technique to use.
                    
                    effect.CurrentTechnique = effect.Techniques[technique];

                    Matrix localWorld = transforms[mesh.ParentBone.Index] * actor.World;

                    effect.Parameters["World"].SetValue(localWorld);
                    effect.Parameters["View"].SetValue(Camera.View);
                    effect.Parameters["Projection"].SetValue(Camera.Projection);
                    
                    // Light Parameters  
                    int LightsCount = Lights.Count;
                    Vector3[] Positions = new Vector3[LightsCount];
                    Vector4[] Colors = new Vector4[LightsCount];
                    float[] Powers = new float[LightsCount];
                    for (int i = 0; i < LightsCount; i++)
                    {
                        Positions.SetValue(Lights[i].Position, i);
                        Colors.SetValue(Lights[i].Color, i);
                        Powers.SetValue(Lights[i].Power, i);
                    }
                    effect.Parameters["LightsPositions"].SetValue(Positions);
                    effect.Parameters["LightsColors"].SetValue(Colors);
                    effect.Parameters["LightsPowers"].SetValue(Powers);
                    // Light Ambient
                    effect.Parameters["LightNumber"].SetValue(Lights.Count);
                }
                mesh.Draw();
            }
        }        

        private void ApplyPostProcess()
        {
            Vector2 resolution = new Vector2(SceneTarget.Width,
                                               SceneTarget.Height);

            Texture2D normalDepthTexture = DepthTarget;
            EffectParameterCollection parameters = PostProcEffect.Parameters;

            parameters["EdgeWidth"].SetValue(EdgeWidth);
            parameters["EdgeIntensity"].SetValue(EdgeIntensity);
            parameters["ScreenResolution"].SetValue(resolution);
            parameters["NormalDepthTexture"].SetValue(normalDepthTexture);

            string effectTechniqueName = "EdgeDetect";

            // Activate the appropriate effect technique.
            PostProcEffect.CurrentTechnique = PostProcEffect.Techniques[effectTechniqueName];

            // Draw a fullscreen sprite to apply the postprocessing effect.
            SpriteBatch spriteBatch = Engine.RenderManager.SpriteBatch;
            spriteBatch.Begin(0, BlendState.Opaque, null, null, null, PostProcEffect);
            spriteBatch.Draw(SceneTarget, Vector2.Zero, Color.White);
            spriteBatch.End();
        }*/
    }
}
